home *** CD-ROM | disk | FTP | other *** search
- INCLUDE TITLE.MAC
- .TITLE <INT_PKG -- Interrupt Vector Interface Routines>
- .SBTTL History
-
- ; int_pkg.asm 17 Nov 83 Craig Milo Rogers at USC/ISI
- ; Debugged in non-DOS, DOS 1, and DOS 2 configurations.
- ; Set to non-DOS for actual use.
- ; Added int_prev().
- ; int_pkg.asm 15 Nov 83 Craig Milo Rogers at USC/ISI
- ; Created this package to change and restore interrupt vectors
- ; on the IBM PC.
-
- .SBHED Overview
-
- ; This package manages interrupt vectors on the IBM PC.
- ;
- ; 1) The package may be compiled to use the DOS calls to get and
- ; set interrupt vectors, or it may be compiled to do these
- ; tasks directly.
- ;
- ; 2) The basic services that this module provides to clients are
- ; to set and restore interrupt vectors. When an interrupt vector
- ; is set, its old contents are saved. The old contents may be
- ; restored upon demand by a client, or when a package termination
- ; (clean-up) call is issued.
- ;
- ; 3) Nested calls to set and restore the same interrupt vector are
- ; not supported.
- ;
- ; 4) The old interrupt vectors are saved in a local storage area.
- ; The length of the storage area is an assembly parameter. A
- ; fixed area was selected over a linked list because a linked
- ; list is more likely to be damaged by a runaway program.
-
- ; Entry points (Lattice C 1.05 calling conventions):
-
- ; void
- ; int_ini() /* Initializes the saved interrupt database.*/
-
- ; bool /* FALSE ==> vector in use or out of mem. */
- ; int_setup(vec, newip, newcs) /* Setup an interrupt vector. */
- ; int vec; /* Interrupt vector number. */
- ; int newip; /* Instruction pointer for interrupt code. */
- ; int newcs; /* Code segment for interrupt code. */
- ; /* Together, newip and newcs are the same
- ; * as a Large model pointer-to-function.
- ; * However, C routines may not be directly
- ; * called this way, since lots of registers
- ; * must be saved and setup first before C
- ; * code can be used. */
-
- ; long /* Actually, a pointer to a "function". */
- ; /* 0L ==> vector not saved, or was empty. */
- ; int_prev(vec) /* Returns prev. contents of the vector. */
- ; int vec; /* Interrupt vector number. */
-
- ; bool /* FALSE ==> vector not in use. */
- ; int_restore(vec) /* Restore an interrupt vector. */
- ; int vec; /* Interrupt vector number. */
-
- ; void
- ; int_trm() /* Terminate, ie restore all vectors. */
-
- .SBHED Declarations
-
- IF1
- INCLUDE DOS.MAC ; C segments.
- INCLUDE BMAC.MAC ; C calling conventions.
- ENDIF
-
-
- ; Here are the two configuration parameters. Ideally these
- ; should come from an include file, not the source file.
-
- NODOS EQU 0 ; 0 ==> Use DOS calls, 1 ==> Avoid DOS.
- NSAVVEC EQU 10 ; Nomber of vectors to handle.
-
-
- ; The following structure saves old interrupt vector contents:
-
- SVEC STRUC ; Saves old vectors.
- SAVVEC DW ? ; Saved vector number.
- SAVIP DW ? ; Saved Instruction Pointer.
- SAVCS DW ? ; Saved Code Segment.
- SVEC ENDS
-
- NOVEC EQU 0FFFFH ; Indicates an unused entry.
-
-
- ; Return Codes:
-
- TRUE EQU 1 ; Truth.
- FALSE EQU 0 ; Falsehood.
-
- .SBHED <Data Storage>
-
- ABS0 SEGMENT AT 0H ; Segment with interrupt vectors.
- ABS0 ENDS
-
- DSEG
-
- SAVAREA SVEC NSAVVEC DUP(<>) ; Saved interrupt vector blocks.
-
- IFE NODOS ; Are we using DOS?
- DOSTYPE DW ? ; Gets the DOS level.
- ENDIF
-
- ENDDS
-
- PSEG
- DB '(C) Copyright Inner Loop Software, 1983'
-
- .SBHED <FINDVEC -- Internal Routine to Find a Vector>
-
- ; Called with the vector in AX.
- ; Returns with a pointer to the vector save block in SI.
- ; Carry clear -- found the vector save entry.
- ; Carry set -- didn't find the vector save entry.
- ; Modifies: CX, SI, CF
-
- FINDVEC PROC NEAR ; Internal routine.
-
- MOV SI,OFFSET SAVAREA ; Address of save area.
- MOV CX,NSAVVEC ; Number of vector save entries.
-
- FINDLOOP:
- CMP [SI].SAVVEC,AX ; Is this the vector?
- JE FOUNDIT ; (yup, too bad)
- ADD SI,TYPE SVEC ; Advance SI to next save entry.
- LOOP FINDLOOP ; Loop for number of save entries.
-
- STC ; Set the carry flag -- not found.
- RET ; Return with error set.
-
- FOUNDIT:
- CLC ; Clear carry - found entry.
- RET ; Return, no error.
-
- FINDVEC ENDP
-
- .SBHED <INT_INI -- Initialize Saved Interrupt Database>
-
- ; void
- ; int_ini() /* Initializes the saved interrupt database.*/
-
- BENTRY INT_INI
-
- MOV SI,OFFSET SAVAREA ; Address of save area.
- MOV CX,NSAVVEC ; Number of vector save entries.
- XOR AX,AX ; Clear AX for a handy source of 0.
-
- INILOOP:
- MOV [SI].SAVVEC,NOVEC ; Indicate no vector present.
- MOV [SI].SAVIP,AX ; Clear saved Instruction Pointer.
- MOV [SI].SAVCS,AX ; Clear saved Code Segment.
- ADD SI,TYPE SVEC ; Advance SI to next save entry.
- LOOP INILOOP ; Loop for number of save entries.
-
- IFE NODOS ; Are we using DOS?
- MOV AH,30H ; Get DOS Version function number.
- INT 21H ; DOS Function Call.
- MOV DOSTYPE,AX ; Save the returned value.
- ENDIF
-
- BEND INT_INI ; That's all for initialization.
-
- .SBHED <INT_SETUP -- Setup an Interrupt Vector>
-
- ; bool /* FALSE ==> vector in use or out of mem. */
- ; int_setup(vec, newip, newcs) /* Setup an interrupt vector. */
- ; int vec; /* Interrupt vector number. */
- ; int newip; /* Instruction pointer for interrupt code. */
- ; int newcs; /* Code segment for interrupt code. */
- ; /* Together, newip and newcs are the same
- ; * as a Large model pointer-to-function.
- ; * However, C routines may not be directly
- ; * called this way, since lots of registers
- ; * must be saved and setup first before C
- ; * code can be used. */
-
- BENTRY INT_SETU <VEC,NEWIP,NEWCS>
-
- MOV AX,VEC ; Vector for which we're looking.
- CALL FINDVEC ; See if already allocated
- JNC SETBAD ; (yup, too bad)
-
- MOV SI,OFFSET SAVAREA ; Address of save area.
- MOV CX,NSAVVEC ; Number of vector save entries.
-
- SETFREE:
- CMP [SI].SAVVEC,NOVEC ; Is this a free entry?
- JE SETVEC ; (yup)
- ADD SI,TYPE SVEC ; Advance SI to next save entry.
- LOOP SETFREE ; Loop for number of save entries.
-
- SETBAD:
- MOV AX,FALSE ; Vector in use, or no free space.
- JMP SHORT SETDONE ; Go return to the user.
-
- SETVEC: ; Let's set the interrupt vector.
- IF NODOS
-
- ; This code copies the old vector contents into the vector save
- ; block and sets the new vector contents, as an atomic operation. This
- ; eliminates the possibility of an interrupt changing the vector's
- ; contents while the vector is being saved.
-
- MOV BX,ABS0 ; Get start of interrupt vectors.
- MOV ES,BX ; ES is vector segment.
- ASSUME ES:ABS0
-
- ; AX still has target vector.
- MOV BX,AX ; Transfer vector number.
- ADD BX,BX ; Convert to vector address.
- ADD BX,BX
- MOV CX,NEWIP ; Get the new vector offset.
- MOV DX,NEWCS ; Get the new vector section.
-
- PUSHF ; Save current interrupt setting.
- CLI ; ******* Disable Interrupts *******
- XCHG CX,ES:[BX] ;;; Set vector's Instruction Ptr.
- XCHG DX,ES:[BX+2] ;;; Set vector's Segment Number.
- MOV [SI].SAVVEC,AX ;;; Mark this save block used.
- MOV [SI].SAVIP,CX ;;; Store the old vector offset.
- MOV [SI].SAVCS,DX ;;; Store the old vector segment.
- POPF ;;; ******* Restore Interrupts *******
- ;;; (Next instruction still disabled)
- ASSUME ES:NOTHING
- ELSE
-
- ; This code saves the old contents of the vector, then sets the new
- ; contents. The operations are not atomic, so there is an implicit
- ; assumption that the interrupt vector will not be changed (by an
- ; interrupt routine) which this routine is running.
-
- CMP BYTE PTR DOSTYPE,2 ; Is this DOS 2 or greater?
- JGE SETDOS2 ; (yup)
-
- ; This system is pre-DOS 2. Save the old vector without DOS.
-
- MOV BX,ABS0 ; Get start of interrupt vectors.
- MOV ES,BX ; ES is vector segment.
- ASSUME ES:ABS0
- ; AX still has target vector.
- MOV BX,AX ; Transfer vector number.
- ADD BX,BX ; Convert to vector address.
- ADD BX,BX
-
- MOV CX,ES:[BX] ; Get vector's Instruction Ptr.
- MOV DX,ES:[BX+2] ; Get vector's Segment Number.
- MOV [SI].SAVIP,CX ; Store the old vector offset.
- MOV [SI].SAVCS,DX ; Store the old vector segment.
- MOV [SI].SAVVEC,AX ; Mark this save block used.
- ASSUME ES:NOTHING
-
- JMP SHORT SETDOSVEC ; Go set the vector.
-
- SETDOS2:
-
- ; Use the DOS 2 call to get old vec. Store the vector number
- ; into the save block last. This interlocks the save block contents
- ; so it can be referenced at interrupt level.
-
- ; AX still has target vector.
- MOV AH,35H ; DOS Get Vector function.
- INT 21H ; DOS Function Call.
- MOV [SI].SAVIP,BX ; Store the old vector offset.
- PUSH ES ; Store the old vector segment
- POP [SI].SAVCS ; via the stack.
- MOV AX,VEC ; Get the vector number again.
- MOV [SI].SAVVEC,AX ; Mark this save block used.
- ; Fall into SETDOSVEC...
-
- SETDOSVEC:
-
- ; Call DOS to set the interrupt vector.
-
- ; Vector number already in AL.
- MOV DX,NEWIP ; Fetch the new vector offset.
- PUSH DS ; Save our data segment.
- PUSH NEWCS ; Fetch the new vector segment.
- POP DS ; Transfer new segment to DS.
- MOV AH,25H ; DOS Set Interrupt Vector function.
- INT 21H ; DOS Function Call.
- POP DS ; Restore our data segment.
- ENDIF
-
- MOV AX,TRUE ; Return TRUE to caller.
- ; Fall into SETDONE...
- SETDONE:
- BEND INT_SETU
-
- .SBHED <INT_PREV -- Return Previous Vector Contents>
-
- ; long /* Actually, a pointer to a "function". */
- ; /* 0L ==> vector not saved, or was empty. */
- ; int_prev(vec) /* Returns prev. contents of the vector. */
- ; int vec; /* Interrupt vector number. */
-
- ; A 0L return can meas two things: either the wrong vector was
- ; supplied to int_prev(), or the vector's previous contents were in fact
- ; zero. 0L is not a significant value for any of the vectors at the
- ; present time, and isn't a reasonable address for a procedure.
- ; However, it is quite possible for a vector to contain 0L if it has
- ; never been used before. So, don't treat 0L as a fatal error, but
- ; don't treat it as a valid procedure, either.
-
- BENTRY INT_PREV <VEC>
-
- MOV AX,VEC ; Vector for which we're looking.
- CALL FINDVEC ; Try to find save block.
- JC PREVERR ; (not found)
- MOV AX,[SI].SAVCS ; AX gets segment.
- MOV BX,[SI].SAVIP ; BX gets offset.
- JMP SHORT PREVDONE ; Go return to the user.
-
- PREVERR:
- XOR AX,AX ; Failed to find target vector.
- XOR BX,BX
-
- PREVDONE:
- BEND INT_PREV ; That's all, return code in AX, BX.
-
- .SBHED <INT_RESTORE -- Restore a Saved Vector>
-
- ; bool /* FALSE ==> vector not in use. */
- ; int_restore(vec) /* Restore an interrupt vector. */
- ; int vec; /* Interrupt vector number. */
-
- BENTRY INT_REST <VEC>
-
- MOV AX,VEC ; Vector for which we're looking.
- CALL FINDVEC ; Look for the saved vector.
- JNC RESTVEC ; (found it)
- MOV AX,FALSE ; Failed to find target vector.
- JMP SHORT RESTDONE ; Go return to the user.
-
- RESTVEC: ; SI points to the save block.
-
- IF NODOS
- MOV BX,AX ; Transfer vector number.
- ADD BX,BX ; Convert to vector address.
- ADD BX,BX
- MOV CX,[SI].SAVIP ; Fetch the saved vector offset.
- MOV DX,[SI].SAVCS ; Fetch the saved vector segment.
- PUSH DS ; Save our data segment.
- MOV AX,ABS0 ; Get start of interrupt vectors.
- MOV DS,AX ; Now work in vector segment.
-
- PUSHF ; Save current interrupt setting.
- CLI ; ******* Disable Interrupts *******
- MOV [BX],CX ;;; Restore vector's Instruction Ptr.
- MOV [BX+2],DX ;;; Restore vector's Segment Number.
- POPF ;;; ******* Restore Interrupts *******
- POP DS ;;; Restore our data segment.
- ELSE
- ; Use DOS call to restore the vector.
- ; Vector number already in AL.
- MOV DX,[SI].SAVIP ; Fetch the saved vector offset.
- PUSH DS ; Save our data segment.
- PUSH [SI].SAVCS ; Fetch the saved vector segment.
- POP DS ; Transfer saved segment to DS.
- MOV AH,25H ; DOS Set Interrupt Vector function.
- INT 21H ; DOS Function Call.
- POP DS ; Restore our data segment.
- ENDIF
-
- MOV [SI].SAVVEC,NOVEC ; Free this saved vector block.
- MOV AX,TRUE ; Return TRUE to caller.
- ; Fall into RESTDONE...
-
- RESTDONE:
- BEND INT_REST ; That's all, return code in AX.
-
- .SBHED <INT_TRM -- Terminate and Restore All Vectors>
-
- ; void
- ; int_trm() /* Terminate, ie restore all vectors. */
-
- BENTRY INT_TRM
-
- MOV SI,OFFSET SAVAREA ; Address of save area.
- MOV CX,NSAVVEC ; Number of vector save entries.
-
- TRMLOOP:
- CMP [SI].SAVVEC,NOVEC ; Is there a vector present?
- JE TRMNEXT ; (nope)
-
- PUSH SI ; Save SI
- PUSH CX ; and CX accross subroutine call.
- BCALL INT_REST <[SI].SAVVEC> ; Call the code to restore the vector.
- POP CX ; Restore saved registers.
- POP SI
-
- TRMNEXT:
- ADD SI,TYPE SVEC ; Advance SI to next save entry.
- LOOP TRMLOOP ; Loop for number of save entries.
-
- BEND INT_TRM ; That's all.
-
- ENDPS
- END
-